export interface ObjectType {
  [key: string]: any
}

/**
 * @author   Chu Wei
 * @date 2023/5/25 11:02
 * @description:去除html中的标签,此方法不会移除&nbsp;等特殊字符
 * @param {str} str 要处理的字符串
 * @return {string} 处理后的字符串
 **/
export function removeHtmlTag(str: string): string {
  return str.replace(/<[^>]+>/g, '')
}

/**
 * @author   Chu Wei
 * @date 2023/5/25 11:10
 * @description:去除html中的标签,此方法会移除&nbsp等实体引用字符
 * @param {str} str 要处理的字符串
 * @return {string} 处理后的字符串
 **/
export function removeHtmlTagAndEntity(str: string): string {
  return str.replace(/<[^>]+>|&[^>]+;/g, '')
}

/**
 * @author   Chu Wei
 * @date 2023/5/25 11:15
 * @description:去除html中的标签,此方法会移除&nbsp等实体引用字符,并且会移除多余的空格
 * @param {str} str 要处理的字符串
 * @return {string} 处理后的字符串
 **/
export function removeHtmlTagAndEntityAndSpace(str: string): string {
  return str.replace(/<[^>]+>|&[^>]+;|\s+/g, '')
}

/**
 * @author Chu Wei
 * @date 2023/5/25 11:37
 * @description:range函数
 * @param {start} start  开始值
 * @param {end} end  结束值
 * @param {step} step  步长
 * @return {Array<number>}
 **/
export function range(start: number, end: number, step = 1): Array<number> {
  if (!end) {
    end = start
    start = 0
  }
  if (start > end) throw new Error('start must less than end')
  return new Array(end - start).fill(start).map((item, index) => start + index * step)
}

/**
 * @author Chu Wei
 * @date 2023/5/25 11:49
 * @description:节流函数
 * @param fn  需要节流的函数
 * @param delay  节流时间
 * @return {Function}
 **/
export function throttle(fn: Function, delay: number = 500): Function {
  let timer: number | null = null
  return function (this: any, ...args: any[]) {
    if (timer) return
    timer = setTimeout(() => {
      fn.apply(this, args)
      timer = null
    }, delay)
  }
}

/**
 * @author   Chu Wei
 * @date 2023/5/25 11:51
 * @description:防抖函数
 * @param {fn} fn  需要防抖的函数
 * @param {delay} delay  防抖时间
 * @param {immediate} immediate  是否立即执行
 * @return {Function}
 **/
export function debounce(fn: Function, delay: number = 500, immediate: boolean = false): Function {
  let timer: number | null = null
  return function (this: any, ...args: any[]) {
    if (immediate) {
      fn.apply(this, args)
      immediate = false
      return
    }
    if (timer) clearTimeout(timer)
    timer = setTimeout(() => {
      fn.apply(this, args)
    }, delay)
  }
}


/**
 * @author   Chu Wei
 * @date 2023/5/25 13:22
 * @description:生成n-m的随机数,不包含m
 * @param {n} n
 * @param {m} m
 * @return {number}
 **/
export function randomN2M(n: number, m: number): number {
  n = +n || 0
  m = +m || 0
  return Math.random() * (m - n) + n
}


/**
 * @author   Chu Wei
 * @date 2023/5/25 13:29
 * @description:生成n-m的随机整数,包含m
 * @param {n} n
 * @param {m} m
 * @return {number}
 **/
export function randomN2MInt(n: number, m: number): number {
  n = +n || 0
  m = +m || 0
  return Math.floor(Math.random() * (m - n + 1) + n)
}

/**
 * @author   Chu Wei
 * @date 2023/5/25 13:32
 * @description:生成指定长度的随机字符串
 * @param {len} len
 * @return {string}
 **/
export function randomString(len: number = 32): string {
  const $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
  const maxPos = $chars.length
  let str = ''
  for (let i = 0; i < len; i++) {
    str += $chars.charAt(Math.floor(Math.random() * maxPos))
  }
  return str
}

/**
 * @author   Chu Wei
 * @date 2023/5/25 14:33
 * @description:获取url参数
 * @return {object} 返回参数对象
 **/
export function getUrlParams(): object {
  const url = window.location.href
  const params = url.split('?')[1]
  const paramsArr = params.split('&')
  const result: ObjectType = {}
  paramsArr.forEach(item => {
    const [key, value] = item.split('=')
    result[key] = value
  })
  return result
}

/**
 * @author   Chu Wei
 * @date 2023/5/25 14:35
 * @description:获取url参数
 * @param {key} key 参数名
 * @return {string} 返回参数值
 **/
export function getUrlParam(key: string): string {
  const url = window.location.href
  const params = url.split('?')[1]
  const paramsArr = params.split('&')
  const result: ObjectType = {}
  paramsArr.forEach(item => {
    const [key, value] = item.split('=')
    result[key] = value
  })
  return result[key]
}

/**
 * @author   Chu Wei
 * @date 2023/5/25 14:39
 * @description:存储localStorage
 * @param {key} key 键
 * @param {value} value 值
 * @return {void}
 **/
export function setStorage(key: string, value: any): void {
  if (!key) return
  localStorage.setItem(key, JSON.stringify(value))
}

/**
 * @author   Chu Wei
 * @date 2023/5/25 14:42
 * @description:获取localStorage
 * @param {key} key 键
 * @return {any} 返回值
 **/
export function getStorage(key: string): any {
  if (!key) return null
  const value = localStorage.getItem(key)
  if (!value) return null
  try {
    return JSON.parse(value)
  } catch (e) {
    return value
  }
}


/**
 * @author   Chu Wei
 * @date 2023/5/25 14:44
 * @description:删除localStorage
 * @param {key} key 键
 * @return {boolean} 是否删除成功
 **/
export function removeStorage(key: string): boolean {
  if (!key) return false
  localStorage.removeItem(key)
  return true
}

/**
 * @author   Chu Wei
 * @date 2023/5/25 14:45
 * @description:清空localStorage
 * @return {boolean} 是否清空成功
 **/
export function clearStorage(): boolean {
  localStorage.clear()
  return true
}

/**
 * @author   Chu Wei
 * @date 2023/5/25 14:45
 * @description:存储sessionStorage
 * @param {key} key 键
 * @param {value} value 值
 **/
export function setSessionStorage(key: string, value: any): void {
  if (!key) return
  sessionStorage.setItem(key, JSON.stringify(value))
}

/**
 * @author   Chu Wei
 * @date 2023/5/25 14:48
 * @description:获取sessionStorage
 * @param {key} key 键
 * @return {any} 返回值
 **/
export function getSessionStorage(key: string): any {
  if (!key) return null
  const value = sessionStorage.getItem(key)
  if (!value) return null
  try {
    return JSON.parse(value)
  } catch (e) {
    return value
  }
}

/**
 * @author   Chu Wei
 * @date 2023/5/25 14:48
 * @description:删除sessionStorage
 * @param {key} key 键
 * @return {boolean} 是否删除成功
 **/
export function removeSessionStorage(key: string): boolean {
  if (!key) return false
  sessionStorage.removeItem(key)
  return true
}

/**
 * @author   Chu Wei
 * @date 2023/5/25 14:49
 * @description:清空sessionStorage
 **/
export function clearSessionStorage(): void {
  sessionStorage.clear()
}

/**
 * @author   Chu Wei
 * @date 2023/5/25 14:50
 * @description:获取对象的类型
 * @param {obj} obj 对象
 * @return {string} 返回类型转换为小写的字符串
 **/
export function getObjType(obj: any): string {
  const str = Object.prototype.toString.call(obj)
  return str.slice(8, -1).toLowerCase()
}

/**
 * @author   Chu Wei
 * @date 2023/5/25 14:52
 * @description:深拷贝
 * @param {obj} obj 对象
 * @return {any} 返回拷贝后的对象,不会拷贝继承的属性
 **/
export function deepClone(obj: any): any {
  const type = getObjType(obj)
  let result: ObjectType
  if (type === 'object') {
    result = {}
  } else if (type === 'array') {
    result = []
  } else {
    return obj
  }
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      const element = obj[key]
      if (getObjType(element) === 'object' || getObjType(element) === 'array')
        result[key] = deepClone(element)
      else {
        result[key] = element
      }
    }
  }
  return result
}

/**
 * @author Chu Wei
 * @date 2023/5/25 16:05
 * @description:校验手机号
 * @param {string} phone 手机号
 * @return {boolean} 是否是手机号
 **/
export function isPhone(phone: string): boolean {
  return /^1\d{10}$/.test(phone)
}

/**
 * @author   Chu Wei
 * @date 2023/5/25 16:05
 * @description:校验邮箱
 * @param {string} email 邮箱
 * @return {boolean} 是否是邮箱
 **/
export function isEmail(email: string): boolean {
  return /^(\w-*\.*)+@(\w-?)+(\.\w{2,})+$/.test(email)
}

/**
 * @author   Chu Wei
 * @date 2023/5/25 16:06
 * @description:校验是不是url
 * @param {string} url url
 * @return {boolean} 是否是url
 **/
export function isUrl(url: string): boolean {
  return /^((https|http|ftp|rtsp|mms)?:\/\/)\S+/.test(url)
}

/**
 * @author   Chu Wei
 * @date 2023/5/25 16:09
 * @description:校验是不是身份证号
 * @param {string} idCard 身份证号
 * @return {boolean} 是否是身份证号
 **/
export function isIdCard(idCard: string): boolean {
  return /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/.test(idCard)
}

/**
 * @author   Chu Wei
 * @date 2023/5/25 16:11
 * @description:校验是不是ios
 * @param {string} ua userAgent
 * @return {boolean} 是否是ios
 **/
export function isIos(ua: string): boolean {
  return /\(i[^;]+;( U;)? CPU.+Mac OS X/.test(ua)
}

/**
 * @author   Chu Wei
 * @date 2023/5/25 16:12
 * @description:校验是不是android
 * @param {string} ua userAgent
 * @return {boolean} 是否是android
 **/
export function isAndroid(ua: string): boolean {
  return /Android/i.test(ua) || /Linux/i.test(ua)
}

/**
 * @author   Chu Wei
 * @date 2023/5/25 16:13
 * @description:校验是不是微信
 * @param {string} ua userAgent
 * @return {boolean} 是否是微信
 **/
export function isWechat(ua: string): boolean {
  return /MicroMessenger/i.test(ua)
}


/**
 * @author   Chu Wei
 * @date 2023/6/12 17:04
 * @description:校验是不是微信浏览器
 **/
export function isWeChatBrowser() {
  return 'WeixinJSBridge' in window
}

/**
 * @author   Chu Wei
 * @date 2023/5/25 16:52
 * @description:唤起文件选择器
 * @param {fileSelectorOptionsType} options 配置项
 * @return {Promise<FileList>} 返回文件FileList
 **/
export interface fileSelectorOptionsType {
  multiple?: boolean,
  accept?: string
}

export function fileSelector(options: fileSelectorOptionsType = {}): Promise<FileList> {
  return new Promise((resolve, reject) => {
    const input = document.createElement('input')
    input.type = 'file'
    if (options.multiple) input.multiple = true
    if (options.accept) input.accept = options.accept
    input.click()
    input.onchange = (e: any) => {
      resolve(e.target.files)
    }
    input.onerror = (e: any) => {
      reject(e)
    }
  })
}

/**
 * @author   Chu Wei
 * @date 2023/5/25 17:17
 * @description:图片选择器
 * @return {Promise<{file:FileList,blob:Blob,base64:string}>} 返回文件FileList,base64,blob
 **/
export function imageSelector(): Promise<{ file: File, blob: Blob, base64: string }> {
  return new Promise(async (resolve, reject) => {
    let files = await fileSelector({accept: 'image/*'})
    const file = files[0]
    const reader = new FileReader()
    reader.readAsDataURL(file)
    reader.onload = (e: any) => {
      const data = {
        file,
        base64: e.target.result,
        blob: file.slice(0, file.size, file.type)
      }
      resolve(data)
    }
    reader.onerror = (e: any) => {
      reject(e)
    }
  })
}


/**
 * @author   Chu Wei
 * @date 2023/5/26 11:30
 * @description:图片压缩
 * @param {File} file 图片的文件File对象
 * @param {number} quality 压缩质量
 * @return {Promise<{blob:Blob,base64:string,file:File}>} 返回文件FileList,base64,blob
 **/
export function imageCompress(file: File, quality: number): Promise<{ blob: Blob, base64: string, file: File }> {
  return new Promise((resolve, reject) => {
    const reader = new FileReader()
    reader.readAsDataURL(file)
    reader.onload = (e: any) => {
      const img = new Image()
      img.src = e.target.result
      img.onload = () => {
        const canvas = document.createElement('canvas')
        const ctx = <CanvasRenderingContext2D>canvas.getContext('2d')
        canvas.width = img.width
        canvas.height = img.height
        ctx.drawImage(img, 0, 0, img.width, img.height)
        const base64 = canvas.toDataURL(file.type, quality)
        canvas.toBlob((blob: any) => {
          resolve({
            blob,
            base64,
            file: new File([blob], file.name, {type: file.type})
          })
        }, file.type, quality)
      }
      img.onerror = (e: any) => {
        reject(e)
      }
    }
  })
}

/**
 * @author   Chu Wei
 * @date 2023/5/26 11:53
 * @description:下载文件
 * @param {string} url 文件地址
 * @param {string} fileName 文件名
 * @return {void}
 **/
export function downloadFile(url: string, fileName: string = '') {
  fetch(url).then(res => res.blob()).then(blob => {
    const a = document.createElement('a')
    a.download = fileName
    a.href = URL.createObjectURL(blob)
    a.click()
    URL.revokeObjectURL(a.href)
  })
}

/**
 * @author   Chu Wei
 * @date 2023/5/26 13:10
 * @description:生成临时文件路径
 * @param {Blob} blob 文件Blob | File 对象
 * @return {string} 临时文件路径
 **/
export function createTempFilePath(blob: Blob | File): string {
  const tempFilePath = URL.createObjectURL(blob)
  URL.revokeObjectURL(tempFilePath)
  return tempFilePath
}
